﻿using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;

namespace Nirvana
{
    public sealed class InstantiateQueue
    {
        private struct InstantiateQueueData
        {
            public GameObject prefab;
            public Action<GameObject> action;
            public int priority;
        }
        private class InstantiateQueueCompare : IComparer<InstantiateQueueData>
        {
            private static InstantiateQueueCompare inst;
            public static InstantiateQueueCompare Init()
            {
                if (inst == null)
                {
                    inst = new InstantiateQueueCompare();
                }
                return inst;
            }
            public int Compare(InstantiateQueueData a, InstantiateQueueData b)
            {
                return a.priority.CompareTo(b.priority);
            }

        }
        private LinkedListNode<Action> queueActionList;
        private PriorityQueue<InstantiateQueueData> priorityqueue = new PriorityQueue<InstantiateQueueData>(InstantiateQueueCompare.Init());
        private static InstantiateQueue _inst;
        public static InstantiateQueue Global { get; set; }
        private int curFrameIndex;
        private int instantiateCountPerFrame = 1;
        public int InstantiateCountPerFrame
        {
            get { return this.instantiateCountPerFrame; }
            set { this.instantiateCountPerFrame = value; }
        }


        public InstantiateQueue()
        {
            this.queueActionList = Scheduler.AddFrameListener(Update);
        }

        ~InstantiateQueue()
        {
            Scheduler.RemoveFrameListener(this.queueActionList);
            queueActionList = null;
        }

        public void Instantiate(GameObject prefab,int index, Action<GameObject> cb)
        {
            if(this.curFrameIndex < this.instantiateCountPerFrame)
            {
                GameObject obj = Singleton<PrefabPool>.Instance.Instantiate(prefab);
                this.curFrameIndex++;
                cb(obj);
            }else
            {
                InstantiateQueueData v = new InstantiateQueueData
                {
                    prefab = prefab,
                    action = cb
                };
                this.priorityqueue.Push(v);
            }
        }

        public void Clear()
        {
            this.priorityqueue.Count = 0;
        }

        private void Update()
        {
            try
            {
                while(this.priorityqueue.Count > 0)
                {
                    if (curFrameIndex >= this.instantiateCountPerFrame) break;

                    InstantiateQueueData _data = this.priorityqueue.Pop();
                    GameObject obj = Singleton<PrefabPool>.Instance.Instantiate(_data.prefab);
                    this.curFrameIndex++;
                    _data.action(obj);
                }
            }
            finally
            {
                this.curFrameIndex = 0;
            }
        }

    }
}

